<?php

namespace backend\modules\rbac\controllers;

use Yii;
use yii\web\Response;
use yii\filters\VerbFilter;
use mdm\admin\components\Helper;
use common\models\rbac\Menu;
use common\helpers\ArrayHelper;
use backend\modules\rbac\models\MenuForm;
use backend\components\Controller;
use common\models\rbac\Route;

/**
 * MenuController implements the CRUD actions for Menu model.
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class MenuController extends Controller {

    public $modelClass = Menu::class;

    /**
     * @inheritdoc
     */
    public function behaviors() {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['post'],
                ],
            ],
        ];
    }

    /**
     * Lists all Menu models.
     * @return mixed
     */
    public function actionIndex() {
        return $this->render('index');
    }

    /**
     * Displays a single Menu model.
     * @param  integer $id
     * @return mixed
     */
    public function actionView($id) {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Displays a single Menu model.
     * @param  integer $id
     * @return mixed
     */
    public function actionClear() {
        return Menu::deleteAll();
    }

    /**
     * Creates a new Menu model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate() {
        $model = new Menu;
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Helper::invalidate();
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Updates an existing Menu model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param  integer $id
     * @return mixed
     */
    public function actionUpdate($id, $scenario = 'default') {
        $model = new MenuForm($id);
        $model->setScenario($scenario);
        $params = Yii::$app->request->post();
        $model->load($params);
        $from = Yii::$app->request->post('_from');
        $ajax = Yii::$app->request->post('ajax');
        if (!$from) {
            Yii::$app->getResponse()->format = Response::FORMAT_JSON;
            if (Yii::$app->request->isAjax && $ajax) {
                return \common\widgets\ActiveForm::validate($model);
            } else {
                $data = $model->save();
                if ($data !== false) {
                    return [
                        'status' => true,
                        'data' => $data
                    ];
                } else {
                    return [
                        'status' => $data,
                    ];
                }
            }
        }
        return $this->renderAjax('update', [
            'model' => $model,
        ]);
    }

    /**
     * Deletes an existing Menu model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param  integer $id
     * @return mixed
     */
    public function actionDelete($id) {
        $this->findModel($id)->delete();
        Helper::invalidate();

        return $this->redirect(['index']);
    }

    /**
     * Deletes an existing Menu model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param  integer $parent
     * @return mixed
     */
    public function actionLoad($parent) {
        Yii::$app->getResponse()->format = Response::FORMAT_JSON;
        if ($parent == "#") {
            $parent = null;
        }
        $menus = Menu::find()->where(['parent' => $parent])->all();
        $data = [];
        foreach ($menus as $menu) {
            $data[] = $menu->toArray();
        }
        return $data;
    }

    /**
     * Deletes an existing Menu model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param  integer $id
     * @return mixed
     */
    public function actionRename() {
        $id = Yii::$app->request->post('id', 0);
        $name = Yii::$app->request->post('name', 0);

        $model = $this->findModel($id);
        $model->name = $name;

        Yii::$app->getResponse()->format = Response::FORMAT_JSON;

        if ($model->save()) {
            return ['status' => true];
        }
        return ['status' => false, 'msg' => print_r($model->getErrors(), true)];
    }

    /**
     * Deletes an existing Menu model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param  integer $id
     * @return mixed
     */
    public function actionVisible($id) {
        $model = $this->findModel($id);
        $model->visibled = abs($model->visibled - 1);
        $model->save(false);
        if (Yii::$app->request->isAjax) {
            Yii::$app->getResponse()->format = Response::FORMAT_JSON;
            return [
                'visibled' => $model->visibled ? true : false
            ];
        }
        return $this->redirect(Yii::$app->request->referrer ? Yii::$app->request->referrer : ['index']);
    }

    /**
     * Deletes an existing Menu model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param  integer $id
     * @return mixed
     */
    public function actionRemove($id) {
        $model = $this->findModel($id);

        $menus = Menu::find()->where(['parent' => $model->id])->all();
        foreach ($menus as $menu) {
            if (!empty($menu->menus)) {
                $ids = ArrayHelper::getColumn($menu->menus, 'id');
                Menu::deleteAll(['id' => $ids]);
            }
            $menu->delete();
        }
        $status = $model->delete();

        if (Yii::$app->request->isAjax) {
            Yii::$app->getResponse()->format = Response::FORMAT_JSON;
            return [
                'status' => $status,
            ];
        }
        return $this->redirect(Yii::$app->request->referrer ? Yii::$app->request->referrer : ['index']);
    }

    /**
     * 清除无效菜单
     * @return type
     */
    public function actionFilter() {
        $model = new Route();
        $routes = $model->getAppRoutes();
        $menus = Menu::find()->all();
        foreach ($menus as $menu) {
            if (isset($routes[$menu->route])) {
                continue;
            }
            $menu->delete();
        }
        return $this->redirect(Yii::$app->request->referrer ? Yii::$app->request->referrer : ['index']);
    }

    /**
     * Refresh cache
     * @return type
     */
    public function actionRefresh() {
        //模块类型菜单
        $modules = Yii::$app->getModules();
        foreach ($modules as $module => $data) {
            $module = '/' . ltrim($module, '/');
            $parent = Menu::findOne([
                'route' => $module . '/*'
            ]);
            if ($parent == null) {
                continue;
            }
            Menu::updateAll(['parent' => $parent->id], [
                'and',
                ['parent' => null],
                ['like', 'route', $module . '/%/*', false]
            ]);
            $data = Menu::find()->where([
                'and',
                ['not', ['parent' => null]],
                ['like', 'route', $module . '/%/*', false],
            ])->all();
            if (empty($data)) {
                continue;
            }
            foreach ($data as $menu) {
                $string = str_replace('*', '%', $menu->route);
                Menu::updateAll(['parent' => $menu->id], [
                    'and',
                    ['parent' => null],
                    ['!=', 'id', $menu->id],
                    ['like', 'route', $string, false],
                ]);
            }
        }

        //应用类型菜单
        $namespace = trim(Yii::$app->controllerNamespace, '\\') . '\\';
        $path = Yii::getAlias('@' . str_replace('\\', '/', $namespace), false);
        $parent = Menu::findOne(['route' => '/*']);

        if (is_dir($path) && $parent != null) {
            foreach (scandir($path) as $file) {
                $moduleName = null;
                if ($file == '.' || $file == '..') {
                    continue;
                }
                if (strcmp(substr($file, -14), 'Controller.php') === 0) {
                    $baseName = substr(basename($file), 0, -14);
                    $name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $baseName));
                    $moduleName = ltrim(str_replace(' ', '-', $name), '-');
                }
                if (!$moduleName) {
                    continue;
                }
                $module = Menu::findOne([
                    'route' => '/' . $moduleName . '/*'
                ]);
                if ($module == null) {
                    continue;
                }
                if (!$module->parent || $module->parent != $parent->id) {
                    $module->parent = $parent->id;
                    $module->save(false);
                }
                Menu::updateAll(['parent' => $module->id], [
                    'and',
                    ['!=', 'route', '/' . $moduleName . '/*'],
                    ['like', 'route', '/' . $moduleName . '/%', false],
                ]);
            }
        }

        return $this->redirect(Yii::$app->request->referrer);
    }

}
